package com.example;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;

public class SimpleRateLimiter {

    private Jedis jedis;

    public SimpleRateLimiter(Jedis jedis) {
        this.jedis = jedis;
    }

    /**
     * 目的：系统要限定用户的某个行为在指定的时间里只能允许发生N 次
     * @param userId 用户
     * @param actionId 行为
     * @param period 时长（时间窗口），单位是毫秒
     * @param maxTimes 最大次数
     * @return
     */
    public boolean isActionAllowed(String userId, String actionId, long period, int maxTimes){
        // 原理：利用Redis sorted-set
        // 以访问时刻的时间戳作为分数，在sorted-set中进行记录
        String key = "rate-limiter:userId:" + userId + ":actionId:" + actionId;
        long currentTimestamp = System.currentTimeMillis();

        Pipeline pipelined = jedis.pipelined();
        pipelined.multi();

        pipelined.zadd(key, currentTimestamp, "" + currentTimestamp);

        // 清理掉时间窗口之外的过期数据
        pipelined.zremrangeByScore(key, 0, currentTimestamp - period);
        Response<Long> count = pipelined.zcard(key);

        pipelined.expire(key, period);

        pipelined.exec();

        return count.get() <= maxTimes;
    }
}
